﻿//
// Copyright (c) 2011 Western Data Solutions (www.westerndatasolutions.com) (Armen Shimoon)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
// documentation files (the "Software"), to deal in the Software without restriction, including without 
// limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 
// the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 
// OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Text;
using WDS.Bencode.Parsing;

namespace WDS.Bencode
{
    /// <summary>
    /// Used for outputting a string of bencoded data from an input bencoded document model
    /// </summary>
    [Obsolete("Use StreamBencodeGenerator as it doesn't have the overhead of constructing string builders all over the place.")]
    public class BencodeGenerator
    {
        /// <summary>
        /// Entry point for generating bencoded data from a bencoded root element
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public string Generate(BencodeElement element)
        {
      
          var sb = new StringBuilder();
  
            var elementType = element.GetType();

            if (typeof(BencodeDictionary).IsAssignableFrom(elementType))
            {
               sb.Append(GenerateDictionary((BencodeDictionary) element));
            }

            else if (typeof(BencodeInteger).IsAssignableFrom(elementType))
            {
                sb.Append(GenerateInteger((BencodeInteger)element));
            }

            else if (typeof(BencodeList).IsAssignableFrom(elementType))
            {
                sb.Append(GenerateList((BencodeList)element));
            }

            else if (typeof(BencodeString).IsAssignableFrom(elementType))
            {
                sb.Append(GenerateString((BencodeString)element));
            }
            else
            {
                throw new BencodeParseException("Encountered unexpected element type of " + elementType.Name);
            }

            return sb.ToString();
        }

        /// <summary>
        /// Renders a bencoded dictionary string
        /// </summary>
        /// <param name="dictionary">The input bencoded dictionary</param>
        /// <returns>A string representation of a bencoded dictionary</returns>
        public string GenerateDictionary(BencodeDictionary dictionary)
        {
           var sb = new StringBuilder();

            sb.Append("d");
            foreach (var kvp in dictionary.Elements)
            {
                sb.Append(Generate(kvp.Key));
                sb.Append(Generate(kvp.Value));
            }
            sb.Append("e");

            return sb.ToString();
        }

        /// <summary>
        /// Renders a bencoded list string
        /// </summary>
        /// <param name="list">The input bencoded list</param>
        /// <returns>A string representation of the bencoded list</returns>
        public string GenerateList(BencodeList list)
        {
            var sb = new StringBuilder();

            sb.Append("l");
            foreach (var item in list.Elements)
            {
                sb.Append(Generate(item));
            }
            sb.Append("e");

            return sb.ToString();
        }

        /// <summary>
        /// Renders a bencoded string string
        /// </summary>
        /// <param name="str">The input bencoded string</param>
        /// <returns>A string representation of the bencoded string</returns>
        public string GenerateString(BencodeString str)
        {
            var sb = new StringBuilder();

            sb.Append(str.Value.Length.ToString());
            sb.Append(":");
            sb.Append(str.Value);

            return sb.ToString();
        }

        /// <summary>
        /// Renders a bencoded integer string
        /// </summary>
        /// <param name="number">The input bencoded integer</param>
        /// <returns>A string representation of the bencoded integer</returns>
        public string GenerateInteger(BencodeInteger number)
        {
            var sb = new StringBuilder();

            sb.Append("i");
            sb.Append(number.Value.ToString());
            sb.Append("e");

            return sb.ToString();
        }
    }
}
